Issue #014
February, 1997


Contents:

Serialization
Introduction to Java Security Part 1 - Virtual Machine
Web Site for Java Indexing Software
Comparing C/C++ and Java Part 14 - Local Declarations
Introduction to AWT Programming Part 1 - A Simple Example
Correction


SERIALIZATION

Imagine that you have a complex data structure in memory, one with
many internal links and fields in it.  At the end of the execution of
an application, you'd like to somehow save this data structure
permanently and then restore it for the next execution of the
application.

Java serialization, new in version 1.1, is a way of doing this.  It's a
mechanism for turning a data structure into a stream of bytes, which
can be written to a file, and then read back in to another data
structure.

Let's look at a simple example of this:

        // file write.java

        import java.io.*;

        public class write {
                private static final int N = 25;

                public static void main(String args[])
                {
                        int x[][] = new int[N][2];

                        for (int i = 0; i < N; i++) {
                                x[i][0] = i;
                                x[i][1] = i * i;
                        }

                        try {
                                FileOutputStream fos =
                                    new FileOutputStream("xxx");
                                ObjectOutputStream oos =
                                    new ObjectOutputStream(fos);
                                oos.writeObject(x);
                                oos.flush();
                                fos.close();
                        }
                        catch (Throwable e) {
                                System.err.println("exception thrown");
                        }
                }
        }

        // file read.java

        import java.io.*;

        public class read {
                public static void main(String args[])
                {
                        int x[][] = null;

                        try {
                                FileInputStream fis =
                                    new FileInputStream("xxx");
                                ObjectInputStream ois =
                                    new ObjectInputStream(fis);
                                x = (int[][])ois.readObject();
                                fis.close();
                        }
                        catch (Throwable e) {
                                System.err.println("exception thrown");
                        }

                        for (int i = 0; i < x.length; i++)
                                System.out.println(x[i][0] + " " + x[i][1]);
                }
        }

In this example, we build a table of squares in a two-dimensional
array, then write the array to a file using writeObject().  We then
read the array back into a separate program using readObject(), casting
the Object reference to the appropriate type.

This operation may not seem like much, but it's hard to do in other
languages, and it's necessary to devise various ad hoc methods for
doing so.

For a class to be serializable, it must implement the Serializable
interface:

        public class xxx implements java.io.Serializable {
                // stuff
        }

This interface is empty, and simply serves as a flag to allow you to
specify which classes are serializable.  In the example above, the
object we serialized was an array, treated as a class type by Java.

Classes which require special handling during serialization can
implement their own writeObject() and readObject() methods.

There are several interesting quirks with serialization which we may
discuss at some point.


INTRODUCTION TO JAVA SECURITY PART 1 - VIRTUAL MACHINE

If you've paid much attention at all to coverage of Java in the
technical and business press, you might have encountered discussions
on Java security, and read about malicious applets and so on.  This is
an interesting and complex subject to contemplate, and we'll spend
several issues looking at it.  There are multiple types and levels of
security to consider.

Let's first look at a short C program:

        void main()
        {
                char c;
                int fd;
                char* p = 0;
                char buf[1024];

                fd = open("data", 0);
                while (read(fd, &c, 1) == 1)
                        *p++ = c;
                close(fd);
        }

This is a mixture of C code and UNIX system calls.  It opens a data
file, reads from it, and places the read characters into a character
buffer.

Unfortunately, this program has a bug, in that the statement:

        p = buf;

was omitted.  So the program will write via the pointer p, but p is
null (0), and the bytes will get written into memory location 0 and
succeeding locations.  If you're running on a DOS machine, this will
probably silently crash your computer.  If you are on a UNIX machine
with virtual address space starting at 0, with text (the program
itself) in low memory, then perhaps you'll get a segmentation
violation error.

The point is that a language like C is "close" to the hardware.  This
is literally true if running with DOS, somewhat less true if using
virtual memory and process protection.  Direct use of system calls for
doing I/O in the example above is another illustration of this point.
This feature of C is both a strength and a weakness.  For example, C
is a good language for writing I/O device drivers, because it's close
to the hardware.

Java takes a different tack.  It has no user-visible pointers, and no
notion of an explicit memory address that you can manipulate or print
out.  With Java it's still possible to make the dumb mistake found in
the example above, but the result would simply be an immediate null
pointer exception.  There is no way to write a byte to physical or
virtual address 0.

Similarly, there is no direct access to system calls.  A Java program
can certainly do I/O to disk files (applets are restricted in this
area), but it can't make system calls itself.

This insulation from the physical machine, via the Java Virtual
Machine, means that program execution tends to be safer as far as
program crashes and interference with other programs go.  The tradeoff
is inability to control the actual physical machine, and some loss of
efficiency.  This implies that Java is suited for a somewhat different
set of applications than a language like C, though of course there is
much overlap between the two.


WEB SITE FOR JAVA INDEXING SOFTWARE

We mentioned last time about the availability of a trial version of
some Java software for indexing files on disk.  If you want to find
out further about this, you can look at the Web site:

        http://www.sni.net/~glenm/index/index.htm


COMPARING C/C++ AND JAVA PART 14 - LOCAL DECLARATIONS

In C, when you declare local variables, it's necessary to group them
all together at the top of a function:

        void f()
        {
                int i;
                double d;
                char* p;

                // stuff
        }

C++ and Java relax this restriction, and allow the declaration of
variables anywhere within the function or method:

        void f()
        {
                int i = 0;

                g(i);

                String s = "xxx";

                h(s);
        }

and so on.  The scope of such declarations is to the end of the block
they're declared in.

It's also possible to declare loop variables within the loop
initialization, as in:

        for (int i = 1; i <= 10; i++) {
                System.out.println(i);
        } 

        i = 37;         // invalid

and the scope is to the end of the for block.

This feature is useful in several ways.  In general, it's best to
minimize the scope of a given declaration, to help in avoiding dumb
programming errors (for example in "recycling" a variable), and doing
so can also help to optimize memory management.

The tradeoff is that introducing declarations in the middle of a block
of code can be confusing to the reader of that code.


INTRODUCTION TO AWT PROGRAMMING PART 1 - A SIMPLE EXAMPLE

In previous issues we've discussed various aspects of applet
programming.  Starting with this issue, we're going to branch out a
bit and consider the more general topic of constructing Graphical User
Interfaces (GUIs) using the AWT (Abstract Windowing Toolkit).  The
examples we present will be actual Java standalone programs rather
than applets.  That is, they'll have their own main() method.

The AWT can be viewed as a high-level abstract means of describing
what a window or windows should look like.  The AWT is actually
implemented differently on different platforms, using windowing
primitives appropriate to each platform.  You can view GUI programming
using the AWT as construction of a complex data structure describing a
window, which is interpreted at program execution time.

Let's start out by looking at a simple example.  This program takes a
single argument, which is the name of a text file, and displays that
file in a scrollable window.  This is kind of like the "more" program
available in UNIX and DOS:

        import java.awt.*;
        import java.io.*;
        
        public class More extends Frame {
        
                private static Button b1 = new Button("New File");
                private static Button b2 = new Button("Exit");
                private static TextArea ta = new TextArea(24, 80);
        
                // handle mouse events
        
                public boolean action(Event e, Object arg)
                {
                        if (e.target instanceof Button) {
                                if (e.target == b1) {
                                        new_file();
                                        return true;
                                }
                                if (e.target == b2) {
                                        System.exit(0);
                                        return true;
                                }
                                return false;
                        }
                        else {
                                return false;
                        } 
                }
        
                // select a new file to view
        
                private void new_file()
                {
                        FileDialog fd = new FileDialog(this, "Open File",
                            FileDialog.LOAD);
                        fd.show();
                        if (fd.getDirectory() == null ||
                            fd.getDirectory().equals(""))
                                return;
                        if (fd.getFile() == null || fd.getFile().equals(""))
                                return;
                        if (fd.getFile().equals("*.*"))
                                return;
                        String fn = fd.getDirectory() + File.separator +
                            fd.getFile();
                        load(fn);
                }
        
                // load a file
        
                private void load(String fn)
                {
                        RandomAccessFile raf = null;
        
                        StringBuffer sb = new StringBuffer();
                        try {
                                String s = null;
                                raf = new RandomAccessFile(fn, "r");
                                while ((s = raf.readLine()) != null) {
                                        sb.append(s);
                                        sb.append('\n');
                                }
                                raf.close();
                        }
                        catch (Throwable e) {
                                System.err.println("file I/O error");
                                System.exit(1);
                        }
                        ta.setText(sb.toString());
                }
        
                // constructor
        
                public More(String title, String fn)
                {
                        super(title);
        
                        resize(600, 450);
        
                        Panel p1 = new Panel();
                        p1.setLayout(new FlowLayout(
                            FlowLayout.CENTER, 100, 0));
                        p1.add(b1);
                        p1.add(b2);
        
                        Panel p2 = new Panel();
                        ta.setEditable(false);
                        p2.add(ta);
        
                        setLayout(new FlowLayout());
        
                        add(p1);
                        add(p2);
        
                        load(fn);
        
                        show();
                }
        
                public static void main(String args[])
                {
                        Frame f = new More("More", args[0]);
                }
        
        }

We start by constructing a Frame, an AWT type suitable for
representing a top-level application window.  We resize the frame, and
then add a couple of panels to it.  What are panels?  A panel is an
AWT entity useful for holding or representing a logical chunk of a
larger interface.  In this example, one of the panels holds a couple
of buttons used for switching files and for exiting, and the other
holds the text area that actually displays the file.

Given two buttons within a panel, or two panels in a frame, how does
the AWT know how to order or arrange these items?  We tell the AWT
about this via a layout manager, in this case by establishing a
FlowLayout object and attaching it to the frame.  This type of layout
arranges objects in rows left to right, and goes to the next row when
it runs out of space.  So the two buttons are arranged left to right
within panel p1.  Panel p2 is laid out on the next "row" after p1,
because you can't fit a large text area right next to a set of buttons.

Actual file loading is straightforward.  We read the lines in from the
file, append them together, and when done call setText() to set the
text for the TextArea object.  A TextArea object already has scroll
bars with it and we don't need to worry about those.

If we want to switch files, we can use a FileDialog entity, which
handles most of the work of file selection.  This brings up a menu of
files that looks similar to what you see on a PC running Windows.

Finally, we define an action() method for handling events in the
frame, in this case file switching or exiting.

This program has a couple of deficiencies, most notably that it reads
a whole file in at one time.  With fairly slow I/O this can be a
problem for very large files.  But the program does serve to
illustrate some of the basics of AWT use.  We'll be looking at some of
these areas in more detail in future issues.


CORRECTION

In issue #013 there was this bit of code, dealing with image filtering:

        int a = rgb & 0xff000000;
        int r = ((rgb & 0xff0000) + 0xff0000) / 2;
        int g = ((rgb & 0xff00) + 0xff00) / 2;
        int b = ((rgb & 0xff) + 0xff) / 2;

This should be:

        int a = rgb & 0xff000000;
        int r = (((rgb & 0xff0000) + 0xff0000) / 2) & 0xff0000;
        int g = (((rgb & 0xff00) + 0xff00) / 2) & 0xff00;
        int b = (((rgb & 0xff) + 0xff) / 2) & 0xff;

Without this change, a low bit can "leak" into the next 8-bit slot in
the 32-bit quantity.

Thanks to David Springer for pointing this out.


ACKNOWLEDGEMENTS

Thanks to Jay Burgess, Thierry Ciot, Irv Kanode, Mike Paluka, Srihari
Sampathkumar, Jason Sharp, and Bob Shore for help with proofreading.


SUBSCRIPTION INFORMATION / BACK ISSUES

To subscribe to the newsletter, send mail to majordomo@world.std.com
with this line as its message body:

subscribe java_letter

Back issues are available via FTP from:

        rmi.net /pub2/glenm/javalett

or on the Web at:

        http://rainbow.rmi.net/~glenm

There is also a C++ newsletter.  To subscribe to it, say:

subscribe c_plus_plus

using the same majordomo@world.std.com address.

-------------------------

Copyright (c) 1997 Glen McCluskey.  All Rights Reserved.

This newsletter may be further distributed provided that it is copied
in its entirety, including the newsletter number at the top and the
copyright and contact information at the bottom.

Glen McCluskey & Associates
Professional Computer Consulting
Internet: glenm@glenmccl.com
Phone: (800) 722-1613 or (970) 490-2462
Fax: (970) 490-2463
FTP: rmi.net /pub2/glenm/javalett (for back issues)
Web: http://rainbow.rmi.net/~glenm
